package com.zlb.app.modules.quartz.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zlb.app.modules.quartz.entity.Job;
import com.zlb.app.modules.quartz.entity.vo.JobQueryVO;
import com.zlb.app.modules.quartz.entity.vo.JobRunVO;
import com.zlb.app.modules.quartz.entity.vo.JobStatusVO;
import com.zlb.app.modules.quartz.enums.JobStatusEnum;
import com.zlb.app.modules.quartz.mapper.JobMapper;
import com.zlb.app.modules.quartz.service.IJobService;
import com.zlb.app.utils.Assert;
import com.zlb.app.utils.CronUtil;
import com.zlb.app.utils.PageUtil;
import com.zlb.app.utils.ScheduleUtil;
import lombok.SneakyThrows;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;

/**
 * @Desc 定时任务调度表 业务实现层
 * @Author zWX1367238
 * @Date 2024-08-27 11:51:15
 */
@Service
public class JobServiceImpl extends ServiceImpl<JobMapper, Job> implements IJobService {

    @Autowired
    private Scheduler scheduler;

    @SneakyThrows
    @PostConstruct
    public void init() {
        scheduler.clear();
        List<Job> jobs = baseMapper.selectList(null);
        for (Job job : jobs) {
            ScheduleUtil.createScheduleJob(scheduler, job);
        }
    }

    @Override
    public IPage<Job> pages(JobQueryVO vo) {
        LambdaQueryWrapper<Job> wrapper = Wrappers.lambdaQuery(Job.class)
                                                            .like(StrUtil.isNotEmpty(vo.getName()), Job::getJobName, vo.getName())
                                                            .like(StrUtil.isNotEmpty(vo.getGroup()), Job::getJobGroup, vo.getGroup())
                                                            .eq(ObjectUtil.isNotEmpty(vo.getStatus()), Job::getStatus, vo.getStatus());
        return baseMapper.selectPage(PageUtil.buildPage(Job.class), wrapper);
    }

    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean saveJob(Job job) {
        // 设默认组
        job.setJobGroup("默认");
        // 默认启用
        job.setStatus(1);
        Assert.isTrue(!CronUtil.isValid(job.getCronExpression()), "Cron表达式无效");
        boolean bool = this.save(job);
        if (bool) {
            ScheduleUtil.createScheduleJob(scheduler, job);
        }
        return bool;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateJob(Job job) {
        Assert.isTrue(!CronUtil.isValid(job.getCronExpression()), "Cron表达式无效");
        Long id = job.getId();
        Assert.isNull(id, "ID不能为空!");
        Job temp = baseMapper.selectById(id);
        Assert.isNull(temp, "该任务不存在或已删除!");
        boolean bool = this.updateById(job);
        if (bool) {
            updateSchedulerJob(job, temp.getJobGroup());
        }
        return bool;
    }

    @Override
    public Boolean deleteJobs(Long[] ids) {
        List<Job> jobs = baseMapper.selectList(new LambdaQueryWrapper<Job>().in(Job::getId, ids));
        boolean bool = this.removeByIds(Arrays.asList(ids));
        if (bool) {
            jobs.forEach(item -> {
                try {
                    scheduler.deleteJob(ScheduleUtil.getJobKey(item.getId(), item.getJobGroup()));
                } catch (SchedulerException e) {
                    throw new RuntimeException(e);
                }
            });
        }
        return bool;
    }

    @Override
    public Job getJobById(Long id) {
        Job job = baseMapper.selectById(id);
        job.setNextValidTime(CronUtil.getNextExecution(job.getCronExpression()));
        return job;
    }

    @Override
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateJobStatus(JobStatusVO jobStatusVO) {
        Job job = baseMapper.selectById(jobStatusVO.getId());
        if (job.getStatus().equals(jobStatusVO.getStatus())) {
            return false;
        }
        Integer status = jobStatusVO.getStatus();
        Long jobId = job.getId();
        String jobGroup = job.getJobGroup();
        LambdaUpdateWrapper<Job> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Job::getId, jobStatusVO.getId()).set(Job::getStatus, status);
        boolean bool = this.update(null, updateWrapper);
        if (bool) {
            if (JobStatusEnum.NORMAL.getValue().equals(status)) {
                scheduler.resumeJob(ScheduleUtil.getJobKey(jobId, jobGroup));
            } else if (JobStatusEnum.PAUSE.getValue().equals(status)) {
                scheduler.pauseJob(ScheduleUtil.getJobKey(jobId, jobGroup));
            }
        }
        return bool;
    }

    @Override
    @SneakyThrows
    public Boolean runJob(JobRunVO jobRunVO) {
        Long jobId = jobRunVO.getId();
        String jobGroup = jobRunVO.getJobGroup();
        Assert.isNull(jobId, "执行任务ID不能为空!");
        scheduler.triggerJob(ScheduleUtil.getJobKey(jobId, jobGroup));
        return true;
    }

    @SneakyThrows
    public void updateSchedulerJob(Job job, String jobGroup) {
        Long jobId = job.getId();
        JobKey jobKey = ScheduleUtil.getJobKey(jobId, jobGroup);
        if (scheduler.checkExists(jobKey)) {
            scheduler.deleteJob(jobKey);
        }
        ScheduleUtil.createScheduleJob(scheduler, job);
    }

}
